unit uGraphForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, uXYList;

type
  TfmGraph = class(TForm)
    PaintBox1: TPaintBox;
    procedure PaintBox1Paint(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    { Private declarations }
    FScale: array[0..1] of single;
    FList: TXYList;
    vx: array[0..1] of single;
    vy: array[0..1] of single;
    procedure CalcScales;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure AddXY(X,Y: single);
  end;

var
  fmGraph: TfmGraph;

implementation

{$R *.dfm}

function min(a,b: single): single;
begin
  if (a<b) then Result := a else Result := b;
end;

function max(a,b: single): single;
begin
  if (a>b) then Result := a else Result := b;
end;

procedure TfmGraph.CalcScales;
var x: integer;
begin
  FScale[0] := 1;
  FScale[1] := 1;

  // Min/max values
  vx[0] := 0; vx[1] := 0;
  for x := 0 to FList.Count-1 do begin
    vx[0] := min(vx[0], FList[x]^.X);
    vx[1] := max(vx[1], FList[x]^.X);
    vy[0] := min(vy[0], FList[x]^.Y);
    vy[1] := max(vy[1], FList[x]^.Y);
  end;

  if (abs(vx[1]-vx[0])>1) then
    FScale[0] := PaintBox1.ClientWidth / abs(vx[1]-vx[0]);
  //if (abs(vy[1]-vy[0])>1) then
    FScale[1] := PaintBox1.ClientHeight / abs(vy[1]-vy[0]);
end;

procedure TfmGraph.PaintBox1Paint(Sender: TObject);
var x,y,px,py: integer;
    dc: HDC;
    st: single;
    txt: string;
begin
  PaintBox1.Canvas.FillRect(Rect(0,0,PaintBox1.ClientWidth,PaintBox1.ClientHeight));
  if (FList.Count < 2) then exit;

  dc := PaintBox1.Canvas.Handle;

  x := 0;
  st := abs(vx[1]-vx[0])/100;
  while (x<100) do begin
    px := trunc(abs(vx[1]-vx[0])/100*x*FScale[0]);
    Windows.MoveToEx(dc, px, 0,nil);
    Windows.LineTo(dc, px, PaintBox1.ClientHeight);

    txt := Format('%.1f Hz', [(vx[1]-vx[0])/100*x+vx[0]]);
    Windows.TextOutA(dc, px, PaintBox1.ClientHeight-16, PAnsiChar(txt), Length(txt));
    Inc(x,10);
  end;

  x := 0;
  st := abs(vy[1]-vy[0])/100;
  while (x<100) do begin
    px := trunc(abs(vy[1]-vy[0])/100*x*FScale[1]);
    Windows.MoveToEx(dc, 0, px, nil);
    Windows.LineTo(dc, PaintBox1.ClientWidth, px);

    txt := Format('%.1f dB', [(vy[1]-vy[0])/100*x+vx[0]]);
    Windows.TextOutA(dc,0,px, PAnsiChar(txt), Length(txt));
    Inc(x,10);
  end;

  px := trunc((FList[0]^.X-vx[0])*FScale[0]);
  py := trunc((FList[0]^.Y-vy[0])*FScale[1]);
  x := 1;
  while (x<FList.Count-1) do try
    Windows.MoveToEx(dc, px, PaintBox1.ClientHeight-py,nil);
    px := trunc((FList[x]^.X-vx[0])*FScale[0]);
    py := trunc((FList[x]^.Y-vy[0])*FScale[1]);
    Windows.LineTo(dc, px, PaintBox1.ClientHeight-py);
    inc(x);
  finally end;
end;

procedure TfmGraph.FormResize(Sender: TObject);
begin
  CalcScales;
end;

constructor TfmGraph.Create(AOwner: TComponent);
begin
  inherited;
  FList := TXYList.Create;
end;

destructor TfmGraph.Destroy;
begin
  inherited;
  FreeAndNil(FList);
end;

procedure TfmGraph.AddXY(X, Y: single);
begin
  FList.Add(X,Y);
end;

end.
